package com.ssy.lingxi.product.serviceImpl.platform;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.product.CategoryEntity;
import com.ssy.lingxi.common.constant.tree.Node;
import com.ssy.lingxi.common.constant.tree.TreeUtils;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.model.vo.SelectVO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.platform.template.api.feign.inner.CategoryWebInnerControllerFeign;
import com.ssy.lingxi.platform.template.api.model.dto.inner.CategorySortDTO;
import com.ssy.lingxi.product.entity.customer.CustomerCategory;
import com.ssy.lingxi.product.entity.platform.Attribute;
import com.ssy.lingxi.product.entity.platform.Category;
import com.ssy.lingxi.product.repository.customer.CustomerCategoryRepository;
import com.ssy.lingxi.product.repository.platform.CategoryRepository;
import com.ssy.lingxi.product.service.platform.ICategoryService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 品类实现类
 * @author jw.chen
 * @version 2.0.0
 * @date 2020/6/22
 */
@Service
public class CategoryServiceImpl implements ICategoryService {

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private CustomerCategoryRepository customerCategoryRepository;

    @Autowired
    private IRedisStringUtils redisStringUtils;

    @Resource
    private CategoryWebInnerControllerFeign categoryWebInnerControllerFeign;

    /**
     * 查询品类树
     * @return Wrapper<?>
     * @param rootNodeId
     */
    @Override
    public List<Node> getCategoryTree(Long rootNodeId, Integer excludeType){
        //查询数据库数据
        List<Category> categoryList;
        if(rootNodeId != null && rootNodeId > 0){
            categoryList = categoryRepository.findByFullIdStartingWith(String.format(Constants.CATEGORY_FULL_ID_NUM, rootNodeId));
        }else{
            categoryList = categoryRepository.findAll();
        }
        if(!categoryList.isEmpty()){
            //组装树结构
            //过滤品类
            if (excludeType != null){
                categoryList =   categoryList.stream().filter(category -> !excludeType.equals(category.getType())).collect(Collectors.toList());
            }
            List<Node> sourceList = categoryList.stream().map(c -> new Node(String.valueOf(c.getId()), String.valueOf(c.getParentId()), c.getName(),false, c.getImageUrl(), c.getSort(), null, new ArrayList<>())).collect(Collectors.toList());
            List<Node> resultList = categoryList.stream().filter(c -> c.getLevel() == 1).map(c -> new Node(String.valueOf(c.getId()), String.valueOf(c.getParentId()), c.getName(),false, c.getImageUrl(), c.getSort(), null, new ArrayList<>())).collect(Collectors.toList());
            return TreeUtils.buildTree(sourceList, resultList);
        }else{
            return new ArrayList<>();
        }
    }

    /**
     * 查询品类
     * @param pageVO
     * @param name
     * @return Page<Attribute>
     */
    @Override
    public Page<Category> getCategoryList(PageVO pageVO, String name){
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());
        if(StringUtils.isNotEmpty(name)){
            return categoryRepository.findByNameContaining(name, page);
        }else{
            return categoryRepository.findAll(page);
        }
    }

    /**
     * 查询品类
     * @return id
     */
    @Override
    public Category getCategory(Long id){
        return categoryRepository.findById(id).orElse(null);
    }

    /**
     * 添加/修改品类
     * @param category
     */
    @Transactional
    @Override
    public String saveOrUpdateCategory(Category category){
        String defaultFullId = String.format(Constants.CATEGORY_FULL_ID_NUM, 0);
        Long id = category.getId();
        String name = category.getName();
        Long parentId = category.getParentId();
        List<Category> old_category;
        //判断是新增还是修改
        if(id != null && id > 0){
            Category currentCategory = categoryRepository.findById(id).orElse(null);
            if(currentCategory == null){
                throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
            }
            //检验名称和key是否重复
            Integer level = currentCategory.getLevel();
            Long currentParentId = currentCategory.getParentId();
            old_category = categoryRepository.findByLevelAndNameAndParentIdAndIdNot(level, name, currentParentId, id);
        }else{
            if(parentId != null && parentId > 0){
                Category parentCategory = categoryRepository.findById(parentId).orElse(null);
                if(parentCategory != null){
                    Integer level = parentCategory.getLevel();
                    old_category = categoryRepository.findByLevelAndName(level + 1, name);
                }else{
                    throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_PARENT_NOT_EXIST);
                }
            }else{
                old_category = categoryRepository.findByLevelAndName(1, name);
            }
        }
        //判断同一等级的品类名称是否重复
        if(!old_category.isEmpty()){
            throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NAME_EXIST);
        }
        if(parentId != null && parentId > 0){
            //判断父节点是否存在
            Category parentCategory = categoryRepository.findById(parentId).orElse(null);
            if(parentCategory == null){
                throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_PARENT_NOT_EXIST);
            }
            category.setLevel(parentCategory.getLevel() + 1);
            String fullId = parentCategory.getFullId();
            category.setFullId(fullId);
        }else{
            category.setLevel(1);
            category.setParentId(0L);
            category.setFullId(defaultFullId);
        }
        //数据库持久化对象
        categoryRepository.saveAndFlush(category);
        String fullId = category.getFullId();
        if(StringUtils.isNotEmpty(fullId) && !defaultFullId.equals(fullId)){
            category.setFullId(fullId + Constants.SPLIT_STR_FULL_ID + String.format(Constants.CATEGORY_FULL_ID_NUM, category.getId()));
        }else{
            category.setFullId(String.format(Constants.CATEGORY_FULL_ID_NUM, category.getId()));
        }
        //数据库持久化对象
        categoryRepository.saveAndFlush(category);
        //调用模板服务-->修改商品排序
        CategorySortDTO dto = new CategorySortDTO();
        dto.setCategoryId(category.getId());
        dto.setSort(category.getSort());
        categoryWebInnerControllerFeign.updateCategorySort(dto);
        //将品类信息缓存到redis
        redisStringUtils.hSet(Constants.REDIS_KEY_CATEGORY, String.valueOf(category.getId()), JSONUtil.toJsonStr(BeanUtil.copyProperties(category, CategoryEntity.class)), Constants.REDIS_PRODUCT_INDEX);
        return ResponseCode.SUCCESS.getMessage();
    }

    /**
     * 删除品类
     * @param id
     * @return
     */
    @Override
    public String deleteCategory(Long id) {
        Category category = categoryRepository.findById(id).orElse(null);
        if(category != null){
            //判断是否存在子节点
            List<Category> subCategoryList = categoryRepository.findByParentId(id);
            if(!subCategoryList.isEmpty()){
                throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_HAVESUB_NOT_DELETE);
            }
            //判断是否存在店铺品类关联
            List<CustomerCategory> customerCategoryList = customerCategoryRepository.findByCategoryId(id);
            if(!customerCategoryList.isEmpty()){
                throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_DELETE);
            }
            //判断是否跟属性绑定
            List<Attribute> attributeList = category.getAttributeList();
            if(attributeList != null && !attributeList.isEmpty()){
                throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_HAVE_ATTRIBUTE_NOT_DELETE);
            }
            categoryRepository.deleteById(id);

            //从redis删除品类
            redisStringUtils.hDel(Constants.REDIS_KEY_CATEGORY, String.valueOf(id), Constants.REDIS_PRODUCT_INDEX);
            return ResponseCode.SUCCESS.getMessage();
        }
        throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
    }

    /**
     * 通过fullId查找完整名称(包括所有父级节点名称)
     * @param fullId
     * @return
     */
    @Override
    public String getFullNameByFullId(String fullId) {
        if(fullId.contains(Constants.SPLIT_STR_FULL_ID)){
            String[] split = fullId.split(Constants.TRANSFER_STR + Constants.SPLIT_STR_FULL_ID);
            String[] idStr = Arrays.stream(split).map(s -> String.valueOf(Long.valueOf(s))).toArray(String[]::new);
            List<String> categoryList = redisStringUtils.hMGet(Constants.REDIS_KEY_CATEGORY, idStr, Constants.REDIS_PRODUCT_INDEX);
            if(categoryList != null && !categoryList.isEmpty()){
                return StringUtils.join(categoryList.stream().map(category -> {
                    if(StringUtils.isNotEmpty(category)){
                        JSONObject jsonObject = JSONUtil.parseObj(category);
                        return jsonObject.getStr("name");
                    }else{
                        return "";
                    }
                }).toArray(String[]::new),"->");
            }else{
                return "";
            }
        }else{
            String category = redisStringUtils.hMGet(Constants.REDIS_KEY_CATEGORY, String.valueOf(Long.valueOf(fullId)), Constants.REDIS_PRODUCT_INDEX);
            if(StringUtils.isNotEmpty(category)){
                JSONObject jsonObject = JSONUtil.parseObj(category);
                return jsonObject.getStr("name");
            }else{
                return "";
            }
        }
    }

    /**
     * 查询平台后台品类最大级别
     * @return
     */
    @Override
    public Integer getCategoryMaxLevel() {
        return categoryRepository.findMaxLevel();
    }

    /**
     * 查询品类下拉框
     * @param name
     * @return
     */
    @Override
    public List<SelectVO> getSelectCategory(String name) {
        //根据条件查询
        Pageable pageable = PageRequest.of(0, Constants.SELECT_COUNT, Sort.by("id").descending());
        Page<Category> page;
        if(StringUtils.isNotEmpty(name)){
            page = categoryRepository.findByNameContaining(name, pageable);
        }else{
            page = categoryRepository.findAll(pageable);
        }
        //转换SelectVO实体
        return page.getContent().stream().map(category -> {
            SelectVO selectVO = new SelectVO();
            selectVO.setId(category.getId());
            selectVO.setName(category.getName());
            return selectVO;
        }).collect(Collectors.toList());
    }

    /**
     * 根据等级查询平台后台品类
     * @param parentId
     * @return
     */
    @Override
    public List<SelectVO> getCategoryByParentId(Long parentId) {
        List<Category> categoryList = categoryRepository.findByParentId(parentId);
        //转换SelectKeyVO实体
        return categoryList.stream().map(category -> {
            SelectVO selectVO = new SelectVO();
            selectVO.setId(category.getId());
            selectVO.setName(category.getName());
            return selectVO;
        }).collect(Collectors.toList());
    }

    /**
     * 品类缓存到redis
     */
    @Async
    @Override
    public void initToRedis() {
        redisStringUtils.del(Constants.REDIS_KEY_CATEGORY, Constants.REDIS_PRODUCT_INDEX);
        List<Category> categoryList = categoryRepository.findAll();
        if(!categoryList.isEmpty()){
            Map<String, String> map = new HashMap<>();
            categoryList.forEach(category -> map.put(String.valueOf(category.getId()), JSONUtil.toJsonStr(BeanUtil.copyProperties(category, CategoryEntity.class))));
            redisStringUtils.hMSet(Constants.REDIS_KEY_CATEGORY, map, Constants.REDIS_PRODUCT_INDEX);
        }
    }

    /**
     * 查询平台后台所有品类的id
     * @return 品类id集合
     */
    @Override
    public List<Long> getCategoryIdList() {
        List<Long> categoryIdList = new ArrayList<>();
        Map<String, String> categoryRedisMap = redisStringUtils.hGetAll(Constants.REDIS_KEY_CATEGORY, Constants.REDIS_PRODUCT_INDEX);
        categoryRedisMap.forEach((key, value) -> {
            Category category = JSONUtil.toBean(value, Category.class);
            categoryIdList.add(category.getId());
        });
        return categoryIdList;
    }

    /**
     * 查询平台后台所有品类的名称
     * @return 品类名称集合
     */
    @Override
    public List<String> getCategoryNameList() {
        List<String> categoryNameList = new ArrayList<>();
        Map<String, String> categoryRedisMap = redisStringUtils.hGetAll(Constants.REDIS_KEY_CATEGORY, Constants.REDIS_PRODUCT_INDEX);
        categoryRedisMap.forEach((key, value) -> {
            Category category = JSONUtil.toBean(value, Category.class);
            String fullId = category.getFullId();
            if(fullId.contains(Constants.SPLIT_STR_FULL_ID)){
                StringBuilder stringBuilder = new StringBuilder();
                String[] split = fullId.split(Constants.TRANSFER_STR + Constants.SPLIT_STR_FULL_ID);
                int categoryId = Integer.parseInt(split[split.length - 1]);
                for (String s : split) {
                    String categoryName = this.getCategoryName(Integer.parseInt(s), categoryRedisMap);
                    if(StringUtils.isNotEmpty(categoryName)){
                        stringBuilder.append(categoryName).append(Constants.UNDERLINE_STR);
                    }
                }
                if(stringBuilder.length() > 0){
                    categoryNameList.add(stringBuilder + String.valueOf(categoryId));
                }
            }else{
                int categoryId = Integer.parseInt(fullId);
                String categoryName = this.getCategoryName(categoryId, categoryRedisMap);
                if(StringUtils.isNotEmpty(categoryName)){
                    categoryNameList.add(categoryName + Constants.UNDERLINE_STR + categoryId);
                }
            }
        });
        return categoryNameList.stream().sorted().collect(Collectors.toList());
    }

    /**
     * redis数据格式中获取品类名称
     * @param categoryId                    品类id
     * @param categoryRedisMap      redis数据
     * @return 品类名称
     */
    private String getCategoryName(int categoryId, Map<String, String> categoryRedisMap){
        String categoryJson = categoryRedisMap.get(String.valueOf(categoryId));
        if(StringUtils.isNotEmpty(categoryJson)){
            Category newCategory = JSONUtil.toBean(categoryJson, Category.class);
            return newCategory.getName();
        }else{
            return "";
        }
    }
}

